﻿using AnesSystem.Models;
using Common;
using MongoDB.Bson;
using MongoDB.Driver;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Reflection;

namespace AnesSystem.Services
{
    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="C">service类型</typeparam>
    /// <typeparam name="T">实体类类型</typeparam>ml
    public abstract class BaseService<C, T>
    {

        #region Variables

        private Common.MongoDBHelper db = HelperManager.Instance.MongoDB;
        private string _className = typeof(T).Name;
        private static C _instance;
        private bool isConvert = true;

        #endregion

        #region Constructor

        public BaseService()
        {

        }

        #endregion

        #region Properties

        public string ClassName
        {
            get
            {
                if (isConvert)
                {
                    return _className.Substring(0, 1).ToLowerInvariant() + _className.Remove(0, 1).Replace("Model", "");
                }
                else
                {
                    return _className;
                }
            }
        }

        public static C Instance
        {
            get
            {
                if (_instance == null)
                {
                    _instance = Activator.CreateInstance<C>();
                }
                return _instance;
            }
        }

        #endregion

        #region Event

        #endregion

        #region Private Methods

        public T CtreatObject()
        {
            Type type = Type.GetType(HospitalConfig.Instance.CurrentHospital.ModelNameSpace + "." + _className);
            if (type != null)
            {
                return (T)Activator.CreateInstance(type);
            }
            else
            {
                return (T)Activator.CreateInstance<T>();
            }
        }


        #endregion

        #region Public/Protected Methods

        public IEnumerable<T> FindAll()
        {
            try
            {
                return FindAll(FilterDefinition<BsonDocument>.Empty);
            }
            catch (Exception ex)
            {
                Common.LogHelper.Error("BaseService", ex);
                return new List<T>();
            }
        }

        public T GetObjById(string id)
        {
            List<T> ret = (List<T>)FindAll(Builders<BsonDocument>.Filter.Eq("_id", new ObjectId(id)));
            if (ret != null && ret.Count != 0)
            {
                return ret[0];
            }
            else
            {
                return default(T);
            }

        }
        public T GetObj(FilterDefinition<BsonDocument> filter)
        {
            List<T> ret = (List<T>)FindAll(filter);
            if (ret != null && ret.Count != 0)
            {
                return ret[0];
            }
            else
            {
                return default(T);
            }

        }


        public IEnumerable<T> FindAll<D>()
        {
            List<D> dList = HelperManager.Instance.MongoDB.FindAsync<D>(new BsonDocument(), ClassName).Result;
            List<T> tList = new List<T>();
            foreach (var dObj in dList)
            {
                PropertyInfo[] tPros = typeof(T).GetProperties();
                T tObj = Activator.CreateInstance<T>();
                foreach (var tPro in tPros)
                {
                    PropertyInfo dPro = typeof(D).GetProperty(tPro.Name.Replace("Model", ""));
                    if (dPro != null)
                    {
                        tPro.SetValue(tObj, dPro.GetValue(dObj));
                    }
                }
                tList.Add(tObj);
            }
            return tList;
        }

        /// <summary>
        /// 查询接口，需要进行新老数据转换时调用
        /// </summary>
        /// <param name="filter"></param>
        /// <returns></returns>
        public IEnumerable<T> FindAll(FilterDefinition<BsonDocument> filter)
        {
            try
            {
                IList<BsonDocument> dList = HelperManager.Instance.MongoDB.FindAsync<BsonDocument>(filter, ClassName).Result;

                List<T> tList = new List<T>();
                foreach (var dObj in dList)
                {
                    T tObj = CtreatObject();
                    if (tObj is PatientLinkModel && tList.Count!=1 &&false)
                    {
                        PatientLinkModel model = tObj as PatientLinkModel;

                        tList.Add(tObj);
                    }
                    else
                    {
                        foreach (var c in dObj)
                        {
                            IEnumerable<PropertyInfo> tPros = tObj.GetType().GetProperties();
                            Util.ExtensionMethods.FillData(c, tObj, tPros);
                        }
                        tList.Add(tObj);
                    }
                }
                return tList;
            }
            catch (Exception ex)
            {
                Common.LogHelper.Error("BaseService", ex);
                return new List<T>();
            }
        }


        public IEnumerable<T> FindAll(FilterDefinition<T> filter)
        {
            return HelperManager.Instance.MongoDB.FindAsync<T>(filter, ClassName).Result;
        }

        public long FindCount(FilterDefinition<BsonDocument> filter = null)
        {
            return HelperManager.Instance.MongoDB.Count<BsonDocument>(filter, ClassName);
        }

        public long Update(T obj)
        {
            return AddUpdate(obj);
        }
        public long Update<D>(T obj)
        {
            PropertyInfo[] dPros = typeof(D).GetProperties();
            D dObj = Activator.CreateInstance<D>();
            foreach (var dPro in dPros)
            {
                PropertyInfo tPro = typeof(T).GetProperty(dPro.Name + "Model");
                if (tPro != null)
                {
                    dPro.SetValue(dObj, tPro.GetValue(obj));
                }
            }
            return HelperManager.Instance.MongoDB.Update<D>(dObj, ClassName).ModifiedCount;
        }


        public void Insert<D>(T obj)
        {
            try
            {
                PropertyInfo[] dPros = typeof(D).GetProperties();
                D tObj = Activator.CreateInstance<D>();
                foreach (var dPro in dPros)
                {
                    PropertyInfo tPro = typeof(T).GetProperty(dPro.Name + "Model");
                    if (tPro != null)
                    {
                        dPro.SetValue(tObj, tPro.GetValue(obj));
                    }
                }
                HelperManager.Instance.MongoDB.Insert<D>(tObj, ClassName);
            }
            catch (Exception ex)
            {
                LogHelper.Error(this.GetType(), ex);
            }
        }
        public void Insert(T obj)
        {
            AddUpdate(obj);
        }

        public long DeleteById<D>(ObjectId id)
        {
            return HelperManager.Instance.MongoDB.Delete<D>(id, ClassName).DeletedCount;
        }
        public long DeleteById(ObjectId id)
        {
            return HelperManager.Instance.MongoDB.Delete<T>(id, ClassName).DeletedCount;
        }
        public long AddUpdate(T obj)
        {

            try
            {
                if (obj is PatientLinkModel)
                {
                    PatintLinkCopyModel p = new PatintLinkCopyModel();
                    p.PatientLink = obj as PatientLinkModel;
                    p.UpdateRoom = DataManager.Instance.CurRoom;
                    PatientLinkCopyService.Instance.Insert(p);
                }
                long result = 0;
                ObjectId id = (ObjectId)(obj.GetType().GetProperty("Id").GetValue(obj));
                PropertyInfo pro = obj.GetType().GetProperty("LastModifyTime");
                if (pro != null)
                {
                    pro.SetValue(obj, DateTime.Now);
                }
                pro = obj.GetType().GetProperty("LastModifyAccount");
                if (pro != null)
                {
                    pro.SetValue(obj, DataManager.Instance.Login);
                }

                if (MongoDBUtil.Instance.ConnectionStatus)
                {
                    if (id == ObjectId.Empty)
                    {
                        HelperManager.Instance.MongoDB.Insert<T>(obj, ClassName);
                    }
                    else
                    {
                        result = HelperManager.Instance.MongoDB.Update<T>(obj, ClassName).ModifiedCount;
                        OffLineManager.Instance.DeleteFile(ClassName);
                    }
                }
                else
                {
                    if (OffLineManager.Instance.SaveFile(ClassName, obj))
                    {
                        result = 1;
                    }
                }
                //if (!HospitalConfig.Instance.CurrentHospital.HospitalCode.Equals(HospitalConfig.HOSPITAL_CODE_CQ_FYBJY)) {
                //    UdpMangager.Instance.SendUpdMsg(ClassName, Udp.ServiceSign.SYSTEMMODIFY, obj);
                //    UdpMangager.Instance.IsNeedSendMessage = true;
                //}               
                return result;
            }
            catch (Exception ex)
            {
                LogHelper.Error(this.GetType(), ex);
                return -1;
            }
        }

        #endregion

        #region EventHandlers

        #endregion
    }
}
